﻿using Serilog;
using System;
using System.IO.Pipes;
using System.Text;
using System.Threading;
using System.Threading.Channels;
using System.Threading.Tasks;

namespace WatchDog.WinService;

public class SendLogToClientService
{
    private Task _worker;
    private readonly CancellationTokenSource _cts = new();

    public static Channel<string> SendChannel { get; private set; } = Channel.CreateBounded<string>(500);

    public SendLogToClientService()
    {
        SendChannel = Channel.CreateBounded<string>(new BoundedChannelOptions(2)
        {  //创建一个指定容量的channel
            SingleWriter = true,
            SingleReader = true,
            Capacity = 500,  //容器容量，会覆盖BoundedChannelOptions构造传入容量，比如目前的4覆盖了上面的2
                             //FullMode = BoundedChannelFullMode.DropWrite, //满了之后忽略要写入的项
                             //FullMode = BoundedChannelFullMode.DropNewest, //满了之后删除最新项，预留空间
                             //FullMode = BoundedChannelFullMode.Wait, //满了阻塞等待读取后腾出空间
            FullMode = BoundedChannelFullMode.DropOldest, //满了之后删除最旧项，留出空间
        });
    }

    public void Start()
    {
        _worker = Task.Factory.StartNew(async () =>
        {
            await WorkerThread();
        }, TaskCreationOptions.LongRunning);
    }

    public void Stop()
    {
        _cts.Cancel();
        _worker = null;
    }

    private async Task WorkerThread()
    {
        while (!_cts.Token.IsCancellationRequested)
        {
            try
            {
                await SendChannel.Reader.WaitToReadAsync();

                //Log.Logger.Information("发送日志到客户端->开始");

                using NamedPipeServerStream server = NewNamedPipeServerStream();

                //Log.Logger.Information("发送日志到客户端->客户端连接成功");

                await foreach (var channel in SendChannel.Reader.ReadAllAsync())
                {
                    //Log.Logger.Information($"发送日志到客户端:{channel}");

                    // 发送消息
                    byte[] buffer = Encoding.UTF8.GetBytes(channel);
                    server.Write(buffer, 0, buffer.Length);
                    server.Flush();
                }
            }
            catch (Exception ex)
            {
                //Log.Logger.Error(ex,"发送日志到客户端窗口时出错！");
            }
        }

        static NamedPipeServerStream NewNamedPipeServerStream()
        {
            var server = new NamedPipeServerStream(
                "WatchDogLogToClientPipe", // 管道名称
                PipeDirection.Out,
                1,
                PipeTransmissionMode.Message,
                PipeOptions.Asynchronous);

            server.WaitForConnection();
            return server;
        }
    }
}
